import java.io.*;
import java.util.*;
import java.math.*;

public class Profile{
	public final String TOKEN = ";";
	
	private Wallet wallet;
	private String name;
	private int counter;
	
	/**
	 * constructor. will only be called by the login GUI. create directory and USERDATA.txt if not exist.
	 * @param name username
	 */
	public Profile(String name){
		this.name = name;
		this.wallet = null;
		this.counter = 0;
		
		//check for existence of folder. create if not exist.
		File userDataFolder = new File("ACCT");
		if (!userDataFolder.exists()){
		    userDataFolder.mkdir();  
		}
		File dataFolder = new File("DATA");
		if (!dataFolder.exists()){
		    dataFolder.mkdir();  
		}
		
		//check for existence of USERDATA.txt. create if not exist.
		File userData = new File("ACCT/USERDATA.txt");
		try{
			userData.createNewFile();
		}
		catch(IOException ioe){
			System.out.printf("creating USERDATA.txt hit IOE\n");
		}
	}
	
	/**
	 * will only be called by login GUI. must pass in password entered in GUI.
	 * This method will 1)accept password from the GUI. 2)open and read USERDATA.txt.
	 * 3) check if user/password exist and is correct.(will auto call readFile() if status = 0)
	 *   
	 * @return 0: OK; 1: User don't exist; 2: User exist. wrong password; negative: error
	 */
	public int login(String password){
		int status = 1;
		FileReader userDataFR;
		BufferedReader userDataBR;
		String inputLine;
		
		//access USERDATA.txt. create a file reader on USERDATA.txt
		File userData = new File("ACCT/USERDATA.txt");
		try{
			userDataFR = new FileReader(userData);
		}
		catch(FileNotFoundException fnfe){
			//this here shouldn't happen
			System.out.printf("USERDATA.txt cannot open\n");
			return -1;
		}
		
		//create a buffered reader on USERDATA.txt
		userDataBR = new BufferedReader(userDataFR);
		try{
			//we read USERDATA.txt until EOF or found matching username.
			inputLine = userDataBR.readLine();
			
			while(inputLine != null){
				String fields[] = inputLine.split(TOKEN);
				
				if(name.compareTo(fields[0]) == 0){				//username found!
					//check password
					if(password.compareTo(fields[1]) == 0){		//correct password
						status = 0;
						break;
					}
					else{
						status = 2;
						break;
					}
				}
				
				inputLine = userDataBR.readLine();
			}
		}
		catch(IOException ioe){
			System.out.printf("IOE while reading USERDATA.txt\n");
			return -1;
		}
		finally{
			try{
				userDataBR.close();
			}
			catch(IOException ioe){
			}
		}
		
		//if login succeed. proceed on with reading data.txt and create wallet.
		if(status == 0){			
			readFile();
		}
		
		return status;
	}	

	/**
	 * this method will 1)read [username].txt for data (FILE MUST EXIST). 2)create a wallet item from data  
	 * @return 0: OK; negative: error
	 */
	public int readFile(){
		BigDecimal balance, salaryAmt;
		Calendar salaryDate, salaryLastPaid; 
		FileReader myFR;
		BufferedReader myBR;
		String itemLine, profileLine;
		Vector<Expense> exList;
		Vector<Income> inList;
		Vector<Bill> billList;
			
		//try to open the file. file always exist. created when making profile.
		File data = new File("DATA/"+name+".txt");	
		
		//create file reader
		try{
			myFR = new FileReader(data);
		}
		catch(FileNotFoundException fnfe){
			//should not happen.
			System.out.printf("DATA/%s.txt not found\n", name);
			return -1;
		}
		
		//create buffered reader
		myBR = new BufferedReader(myFR); 
		
		try{
			//read profile info
			profileLine = myBR.readLine();
			String profileFields[] = profileLine.split(TOKEN);
			salaryAmt = new BigDecimal(profileFields[0]);			//salary amt
			salaryDate = Helper.strToCal(profileFields[1]);				//salary date
			salaryLastPaid = Helper.strToCal(profileFields[2]);			//salary last paid date
			balance = new BigDecimal(profileFields[3]);				//balance
			
			//declare vector of expense, income and bill
			exList = new Vector<Expense>();
			inList = new Vector<Income>();
			billList = new Vector<Bill>();
	
			itemLine = myBR.readLine();
			while(itemLine != null){
				String itemFields[] = itemLine.split(TOKEN);
				
				//parse date		
				Calendar date = Helper.strToCal(itemFields[2]);	//item date
				
				//we parse the line depend on the type of item
				switch(itemFields[0].charAt(0)){
					case 'e':
						Expense exItem = new Expense(itemFields[1], date, new BigDecimal(itemFields[3]), itemFields[4], itemFields[5], ++counter);
						exList.add(exItem);
						break;
					
					case 'i':
						Income inItem = new Income(itemFields[1], date, new BigDecimal(itemFields[3]), ++counter);
						inList.add(inItem);
						break;
					
					case 'b':
						Calendar lastPaidDate = Helper.strToCal(itemFields[3]);
						Bill billItem = new Bill(itemFields[1], date, lastPaidDate, ++counter);
						billList.add(billItem);
						break;
				}

				itemLine = myBR.readLine();
			}
		}
		catch(IOException e){
			System.out.println("die while reading");
			return -1;
		}
		finally{
			try{
				myBR.close();
			}
			catch(IOException e){
				//do nothing
			}
		}
	
		//we create our wallet item
		wallet = new Wallet(balance, exList, inList, billList, new Salary(salaryAmt, salaryLastPaid, salaryDate), (counter+1));
	
		return 0;
	}
	
	/**
	 * This method will 1)open [username].txt (doesnt matter if exist). 2)write to it.(wallet must be present)
	 * @return 0 if succeed. -1 if fail
	 */
	public int writeFile(){
		FileWriter myFW;
		BufferedWriter myBW;
		Vector<Expense> exList;
		Vector<Income> inList;
		Vector<Bill> billList;
		
		//try to open file. doesn't matter if exist or not.
		File data = new File("DATA/"+name+".txt");
		
		//create file writer
		try{
			myFW = new FileWriter(data);
		}
		catch(IOException ioe){
			System.out.printf("ioe when opening DATA/%s.txt\n", name);
			return -1;
		}
		
		//create buffered writer
		myBW = new BufferedWriter(myFW); 
		
		//create profileLine
		Salary mySalary = wallet.getSalary();
		String profileLine = mySalary.getAmt().toString() + TOKEN;
		profileLine = profileLine + Helper.calToStr(mySalary.getNextPayDate()) + TOKEN;
		profileLine = profileLine + Helper.calToStr(mySalary.getLastPaidDate()) + TOKEN;
		profileLine = profileLine + wallet.getBalance().toString() + "\n";
		
		try{
			//write profileLine
			myBW.write(profileLine, 0, profileLine.length());
			
			//get 3 list.
			exList = wallet.getExpenseList();
			inList = wallet.getIncomeList();
			billList = wallet.getBillList();
			
			//write item line
			for(Expense e : exList){
				String itemLine = expToStr(e);
				myBW.write(itemLine, 0, itemLine.length());
			}
			for(Income i : inList){
				String itemLine = incToStr(i);
				myBW.write(itemLine, 0, itemLine.length());
			}
			for(Bill b : billList){
				String itemLine = billToStr(b);
				myBW.write(itemLine, 0, itemLine.length());
			}
		}
		catch(IOException ioe){
			System.out.printf("ioe while writing to DATA/%s.txt\n", name);
			return -1;
		}
		finally{
			try{
				myBW.close();
			}
			catch(IOException ioe){
			}
			
		}
		
		return 0;
	}
	
	/**
	 * This method will only be called by GUI. 1)GUI will pass in parameter. 2)append user and pass to USERDATA.txt
	 * 3)create user.txt with profile line. does not perform readfile() so wallet is not set
	 * @param password
	 * @param salaryAmt
	 * @param payDay
	 * @param balance
	 * @return 0: OK; -1: error
	 */
	public int createAcct(String password, BigDecimal salaryAmt, Calendar payDay, BigDecimal balance){
		FileWriter userDataFW, dataFW;
		BufferedWriter userDataBW, dataBW;
		
		//access USERDATA.txt. create a file reader on USERDATA.txt
		File userData = new File("ACCT/USERDATA.txt");
		try{
			userDataFW = new FileWriter(userData, true);
		}
		catch(IOException ioe){
			//this here shouldn't happen
			System.out.printf("USERDATA.txt cannot open\n");
			return -1;
		}
		
		//create a buffered writer on USERDATA.txt
		userDataBW = new BufferedWriter(userDataFW);
		
		try{
			userDataBW.write(name + TOKEN + password + "\n");
		}
		catch(IOException ioe){
			System.out.printf("ioe while writing to ACCT/USERDATA.txt\n");
			return -1;
		}
		finally{
			try{
				userDataBW.close();
			}
			catch(IOException ioe){
			}
		}
		
		//create data
		File data = new File("DATA/"+name+".txt");
		try{
			data.createNewFile();
		}
		catch(IOException ioe){
			System.out.printf("ioe when creating DATA/%s.txt\n", name);
			return -1;
		}
		
		//create file writer on data
		try{
			dataFW = new FileWriter(data);
		}
		catch(IOException ioe){
			//this here shouldn't happen
			System.out.printf("DATA/%s.txt cannot open\n", name);
			return -1;
		}
		
		//create a buffered writer on data.txt
		dataBW = new BufferedWriter(dataFW);
		
		try{
			dataBW.write(salaryAmt.toString() + TOKEN + Helper.calToStr(payDay) + TOKEN + Helper.calToStr(Calendar.getInstance()) + TOKEN + balance.toString() + "\n");
		}
		catch(IOException ioe){
			System.out.printf("ioe when writing to DATA/%s.txt\n", name);
			return -1;
		}
		finally{
			try{
				dataBW.close();
			}
			catch(IOException ioe){
			}
		}
		
		return 0;
	}
	
	//getter method below ====================================================================
	public Wallet getWallet() { return wallet;}

	public String getName() { return name;}

	public int getCounter() { return counter;}
	
	//helper method below ====================================================================
	private String expToStr(Expense e){
		String str = "e" + TOKEN;
		str = str + e.getDescription() + TOKEN;
		str = str + Helper.calToStr(e.getDate()) + TOKEN;
		str = str + e.getAmt().toString() + TOKEN;
		str = str + e.getCategory() + TOKEN;
		str = str + e.getPaymentMethod() + "\n";
		
		return str;
	}
	
	private String incToStr(Income i){
		String str = "i" + TOKEN;
		str = str + i.getDescription() + TOKEN;
		str = str + Helper.calToStr(i.getDate()) + TOKEN;
		str = str + i.getAmt().toString() + "\n";
		
		return str;
	}
	
	private String billToStr(Bill b){
		String str = "b" + TOKEN;
		str = str + b.getDescription() + TOKEN;
		str = str + Helper.calToStr(b.getDate()) + TOKEN;
		str = str + Helper.calToStr(b.getNextPayDate()) + "\n";
		
		return str;
	}
}